#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <pthread.h>
#include <memory>
#include <string>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/wait.h>
#include <unordered_set>
#include "public.h"
#include <strings.h>
#include <dirent.h>
#include "service.h"

using namespace std;

// fileserver的控制开关
bool isFileServerRunning = true;
// 存储所有子进程的pid
unordered_set<pid_t> pidsets;


// 响应ctrl-c信号，
void SigIntHandle(int)
{
    isFileServerRunning = false;
}

// 处理子进程结束信号，防止僵尸进程出现
void SigChldHandler(int)
{
    pid_t pid;
    while((pid = waitpid(-1, NULL, WNOHANG)) > 0)
    {
        pidsets.erase(pid);
    }
}

// 设置非阻塞模式
void SetNonBlocking(int fd)
{
    int opt = fcntl(fd, F_GETFL);
    opt |= O_NONBLOCK; // 添加非阻塞标志
    fcntl(fd, F_SETFL, opt);
}

// 子进程处理客户端的业务的
void ClientProcess(int clientfd)
{
    // 从clientfd接收buffer
    char buffer[1024] = {0};

    for (;;)
    {
        bzero(buffer, 1024);
        int ret = recv(clientfd, buffer, 1024, 0);
        CheckErr(ret, "recv err");
        if (ret == 0) // 对端断开了
        {
            close(clientfd);
            exit(0);
        }

        // 解析DataPacket
        DataPacket *dp = (DataPacket*)buffer;
        switch(dp->type)
        {
        case TYPE_DIR:
            ProcessDir(clientfd, dp);
            break;
        case TYPE_UPLOAD:
            ProcessUpload(clientfd, dp);
            break;
        default:
            break;
        }
    }
}

// 文件服务器实现
int main(int argc, char **argv)
{
    int ret = 0;

    signal(SIGINT, SigIntHandle);
    signal(SIGCHLD, SigChldHandler);

    if (argc < 3)
    {
        cout << "usage: ./command ip port" << endl;
        exit(-1);
    }

    // 解析参数
    char *ip = argv[1];
    int port = atoi(argv[2]);

    int listenfd = socket(AF_INET, SOCK_STREAM, 0);
    CheckErr(listenfd, "socket err");

    // 设置listenfd工作在非阻塞模式
    SetNonBlocking(listenfd);

    struct sockaddr_in s;
    s.sin_family = AF_INET;
    s.sin_port = htons(port);
    s.sin_addr.s_addr = inet_addr(ip);

    ret = bind(listenfd, (struct sockaddr*)&s, sizeof(s));
    CheckErr(ret, "bind err");
    
    ret = listen(listenfd, 1024);
    CheckErr(ret, "listen err");

    struct sockaddr_in c;
    socklen_t clen = sizeof(c);
    while (isFileServerRunning)
    {
        // listenfd工作在非阻塞模式，所以accept不会阻塞线程
        int clientfd = accept(listenfd, (sockaddr*)&c, &clen);
        if (clientfd < 0)
        {
            if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                // 非阻塞返回
                continue;
            }
            CheckErr(clientfd, "accept err");
        }

        // 创建子进程给客户端提供服务
        pid_t pid = fork();
        CheckErr(pid, "accept err");

        if (pid > 0)
        {
            // 父进程
            close(clientfd);
            pidsets.emplace(pid);
        }
        else
        {
            // 子进程
            close(listenfd);
            ClientProcess(clientfd);
            exit(0);
        }
    }

    close(listenfd);

    cout << "notify all child process quit...";
    for (auto pid : pidsets)
    {
        kill(pid, SIGKILL);  // 退出所有的子进程
    }
    cout << "fileserver quit!" << endl;

    return 0;
}